import {redisSQLDatabase} from 'TYPE'
import {cache} from '../cache'
import knex from '../sql'

declare module 'knex/types/tables' {
    interface UserRelative {
        uid1: number
        uid2: number
        relationship: string
        value: string
    }
    interface Tables {
        user_relatives_relations: UserRelative
    }
}
/**
 * user1 --relative (relationship)--> user2
 * A relative relationship from user1 to user2.
 * 
 */
class UserRelativeDB implements redisSQLDatabase {
    relationships = ['follow']
    static keys(uid1: number, uid2: number, relationship: string) {
        return [`relative_from:${relationship}:user:${uid1}`, `relative_to:${relationship}:user:${uid2}`]
    }
    async queryRelativeToByUid(uid: number, relationship: string) {
        const key = UserRelativeDB.keys(0, uid, relationship)[1]
        const uids: string[] = await cache.SMEMBERS(key) // redis set
        return uids
    }
    async queryRelativeFromByUid(uid: number, relationship: string) {
        const key = UserRelativeDB.keys(uid, 0, relationship)[0]
        const uids: string[] = await cache.SMEMBERS(key) // redis set
        return uids
    }
    async hasRelative(uid1: number, uid2: number, relationship: string) {
        const key = UserRelativeDB.keys(uid1, uid2, relationship)[0]
        const flag: boolean = await cache.SISMEMBER(key, String(uid2))
        return flag
    }
    async addRelative(uid1: number, uid2: number, relationship: string) {
        if (await this.hasRelative(uid1, uid2, relationship)) {
            return true
        }
        const [key1, key2] = UserRelativeDB.keys(uid1, uid2, relationship)
        await cache.SADD(key1, String(uid2))
        await cache.SADD(key2, String(uid1))
        let flag = false
        try {
            await knex('user_relative_relations').insert({uid1, uid2, relationship, value: 'true'}).then(num => {
                if (num.length > 0) flag = true
            })
        } catch (error) {
            await knex('user_relative_relations').where({uid1, uid2, relationship}).update({value: 'true'}).then(num => {
                if (num > 0) flag = true
            })
        }
        return flag
    }
    async loadAll() {
        await cache.keys('relative_*').then(async (keys) => {
            for (const key of keys) {
                await cache.del(key)
            }
        })
        await knex('user_relative_relations').select().then(rs => {
            for (const r of rs) {
                if (!r.value || r.value === 'false') continue
                const {uid1, uid2, relationship} = r
                const [key1, key2] = UserRelativeDB.keys(uid1, uid2, relationship)
                cache.SADD(key1, String(uid2))
                cache.SADD(key2, String(uid1))
            }
        })
    }
    async removeRelative(uid1: number, uid2: number, relationship: string) {
        const [key1, key2] = UserRelativeDB.keys(uid1, uid2, relationship)
        await cache.SREM(key1, String(uid2))
        await cache.SREM(key2, String(uid1))
        let flag = false
        await knex('user_relative_relations').where({uid1, uid2, relationship}).update({value: 'false'}).then(num => {
            if (num > 0) flag = true
        })
        return flag
    }
}
export const userRelativeDB = new UserRelativeDB()
